package com.example.a41;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;

import java.util.List;

public class A41Application_1 {

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        // 是否允许 Bean 定义 被覆盖
        context.getDefaultListableBeanFactory().setAllowBeanDefinitionOverriding(false);
        context.registerBean("config", Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>");
        System.out.println(context.getBean(Bean1.class));

        /*
            小结:
                1. 自动配置类本质上就是一个配置类而已，只是用 META-INF/spring.factories管理，与应用配置类解耦
                2. @Enable 大头的注解本质就是利用了 @Import
                3. @Import 配合 DeferredImportSelector 即可实现导入，selectImports 方法的返回值即为要导入的配置类名
                4. DeferredImportSelector 的导入会在最后执行，为的是让其他配置优先解析
         */
    }

    @Configuration // 本项目的配置类
    @Import(MyImportSelector.class)
    static class Config { // 本项目配置类
        @Bean
        public Bean1 bean1() {
            return new Bean1("本项目");
        }
    }

    static class MyImportSelector implements DeferredImportSelector {

        // ⬇️该方法从 META-INF/spring.factories 读取自动配置类名，返回的 String[] 即为要导入的配置类
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//            return new String[]{AutoConfiguration1.class.getName(), AutoConfiguration2.class.getName()};
            System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
            for (String name : SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, null)) {
                System.out.println(name);
            }
            System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");

            // 到配置文件中去读取这些第三方配置类的名字
            List<String> names = SpringFactoriesLoader.loadFactoryNames(MyImportSelector.class, null);
            return names.toArray(String[]::new);
        }
    }

    @Configuration // 第三方的配置类
    static class AutoConfiguration1 {

        @Bean
        @ConditionalOnMissingBean
        public Bean1 bean1() {
            return new Bean1("第三方");
        }

    }

    static class Bean1 {

        private String name;

        public Bean1() {
        }

        public Bean1(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Bean1{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

    @Configuration // 第三方的配置类
    static class AutoConfiguration2 {

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }

    }

    static class Bean2 {
    }

}
